import binascii
import ctypes
import logging
from ctypes import *

import numpy as np
from dbc import DBCParser
from zlgcan import *
from zuds_structure import *
import platform
import threading
import time
import datetime
import os  # 添加os模块导入
from zlgdbc import *

current_dir = os.path.dirname(os.path.abspath(__file__))    # 获取当前文件所在目录
parent_dir = os.path.dirname(current_dir)   # 获取当前文件所在目录的上层目录
grand_parent_dir = os.path.dirname(parent_dir)  # 获取上层目录的再上一层目录
sys.path.append(grand_parent_dir)   # 将再上一层目录添加到 sys.path 中
import Set_up

# 配置logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 全局变量，用于控制接收线程的启动和停止
START_RECEIVE_FLAG = 0

# 定义全局变量 zcanlib
zcanlib = ZCAN()


# 定义结构体用于存放UDS的参数内容
class PARAM_DATA(Structure):
    _pack_ = 1
    _fields_ = [("data", c_ubyte * 4096)]

# 定义通道参数结构体
class CHANNEL_PARAM(Structure):
    _fields_ = [
        ("channel_handle", c_uint32),  # 通道句柄
        ("Extend_Flag", c_uint32),  # 0-standard_frame, 1-extern_frame
        ("CANFD_type", c_uint32),  # 0-can,1-canfd
        ("trans_version", c_uint32)  # 0-ISO15765-2004,1-ISO15765-2016
    ]

# 发送回调函数，用于将UDS帧转换为CAN或CANFD帧并发送
@WINFUNCTYPE(c_uint32, POINTER(CHANNEL_PARAM), POINTER(ZUDS_FRAME), c_uint32)
def transmit_callback(ctx, frame, count):
    try:
        if ctx.contents.CANFD_type:
            zcanfd_data = (ZCAN_TransmitFD_Data * count)()
            memset(zcanfd_data, 0, sizeof(zcanfd_data))
            for i in range(count):
                zcanfd_data[i].frame.can_id = frame[i].id
                if ctx.contents.Extend_Flag:
                    zcanfd_data[i].frame.eff = 1
                zcanfd_data[i].frame.len = frame[i].data_len
                zcanfd_data[i].frame.__pad = 0x08  # 设置发送回显
                for j in range(frame[i].data_len):
                    zcanfd_data[i].frame.data[j] = frame[i].data[j]
            result = zcanlib.TransmitFD(ctx.contents.channel_handle, zcanfd_data, count)
        else:
            zcan_data = (ZCAN_Transmit_Data * count)()
            memset(zcan_data, 0, sizeof(zcan_data))
            for i in range(count):
                zcan_data[i].frame.can_id = frame[i].id
                if ctx.contents.Extend_Flag:
                    zcan_data[i].frame.eff = 1
                zcan_data[i].frame.can_dlc = frame[i].data_len
                for j in range(frame[i].data_len):
                    zcan_data[i].frame.data[j] = frame[i].data[j]
            result = zcanlib.Transmit(ctx.contents.channel_handle, zcan_data, count)
        return 0 if result == count else 1
    except Exception as e:
        logging.error(f"Error in transmit_callback: {e}")
        return 1

# 全局变量，用于控制是否保存日志到文件
SAVE_LOG_FLAG = False
# 日志文件名
LOG_FILE_NAME = "canfd_specific_log.txt"

# UDS库类，封装了UDS库的操作
class ZUDS:
    def __init__(self):
        try:
            if platform.system() == "Windows":
                try:
                    # 尝试加载 commDriver/zlg/zuds.dll
                    self._dll = windll.LoadLibrary("commDriver/zlg/zuds.dll")
                except FileNotFoundError:
                    # 若 commDriver/zlg/zuds.dll 不存在，尝试加载 ./zuds.dll
                    self._dll = windll.LoadLibrary("./zuds.dll")
            else:
                logging.warning("No support now!")
                self._dll = None
            if self._dll is None:
                raise FileNotFoundError("DLL couldn't be loaded!")
        except Exception as e:
            logging.error(f"Error loading DLL: {e}")

    def _call_dll_function(self, func_name, *args):
        func = getattr(self._dll, func_name, None)
        if func:
            try:
                return func(*args)
            except Exception as e:
                logging.error(f"Exception on {func_name}: {e}")
        return None

    def Uds_Init(self, type_):
        return self._call_dll_function("ZUDS_Init", type_)

    def Uds_SetTransmitHandler(self, zuds_handle, ctx):
        return self._call_dll_function("ZUDS_SetTransmitHandler", zuds_handle, ctx, transmit_callback)

    def Uds_Request(self, handle, request, response):
        return self._call_dll_function("ZUDS_Request", handle, byref(request), byref(response))

    def Uds_Onreceive(self, handle, uds_frame):
        return self._call_dll_function("ZUDS_OnReceive", handle, byref(uds_frame))

    def Uds_SetParam(self, handle, type_, param):
        return self._call_dll_function("ZUDS_SetParam", handle, type_, byref(param))

    def Uds_SetTesterPresent(self, handle, enable, param):
        return self._call_dll_function("ZUDS_SetTesterPresent", handle, enable, byref(param))

    def Uds_Release(self, handle):
        return self._call_dll_function("ZUDS_Release", handle)

    def Uds_Stop(self, handle):
        return self._call_dll_function("ZUDS_Stop", handle)


class UDSController:
    """
    UDSController类封装了UDS通信的主要操作，包括CAN设备的打开、UDS的初始化、请求的发送和响应的处理等。
    """
    def __init__(self,device_type=ZCAN_USBCANFD_200U, device_index=0,chn_index=0,abit=500000,bbit=2000000):
        """
        初始化UDSController类的实例。
        初始化ZCAN和ZUDS库的实例，并将设备句柄、通道句柄、UDS句柄等初始化为None。
        """
        self.zcanlib = ZCAN()
        self.zudslib = ZUDS()
        self.zdbclib = DBCProcessor()
        self.device_handle = None
        self.chn_handle_0 = None
        self.uds_handle = None
        self.chn_param = None
        self.read_thread_ = None
        self.device_type = device_type
        self.device_index = device_index
        self.chn_index = chn_index
        self.abit = abit
        self.bbit = bbit
        self.current_data = []  # 新增属性，用于存储当前要发送的数据
        self.signal_cantype_dict={}  # 用于存储每个信号ID对应的CAN类型
        self.signal_data_dict = {}  # 用于存储每个信号ID对应的当前数据
        self.signal_thread_dict = {}  # 用于存储每个信号ID对应的线程
        self.signal_stop_event_dict = {}  # 用于存储每个信号ID对应的停止事件
        self.signal_pause_event_dict = {}  # 用于存储每个信号ID的暂停事件
        self.frame_timestamps = {}  # 新增：存储报文ID和最后时间戳的字典

        self.signal_monitor_thread = None
        self.signal_monitor_running = threading.Event()
        self.signal_monitor_interval = 0.1  # 默认监控间隔100ms
        self.signal_change_callbacks = {}  # 信号变化回调函数字典

        self.signal_receive_callbacks = {}  # 新增信号接收回调字典
        self.received_signal_data = {}     # 新增接收数据存储

    
    def _handle_received_signal(self, frame_id, data):
        """处理接收到的信号数据"""
        # 记录原始数据
        self.received_signal_data[frame_id] = data
        
        # 触发注册的回调
        if frame_id in self.signal_receive_callbacks:
            try:
                self.signal_receive_callbacks[frame_id](frame_id, data)
            except Exception as e:
                logging.error(f"Signal receive callback error: {str(e)}")

    def register_signal_receiver(self, frame_id, callback):
        """
        注册信号接收回调
        :param frame_id: 要监听的信号ID 
        :param callback: 回调函数格式: func(frame_id, data)
        """
        self.signal_receive_callbacks[frame_id] = callback

    def unregister_signal_receiver(self, frame_id):
        """注销信号接收监听"""
        if frame_id in self.signal_receive_callbacks:
            del self.signal_receive_callbacks[frame_id]


    def get_frame_interval(self, frame_id):
        """
        获取指定报文ID的接收间隔
        :param frame_id: 要检测的报文ID
        :return: 与上一帧的间隔时间（秒），如果是首帧返回None
        """
        current_time = time.time()
        if frame_id in self.frame_timestamps:
            interval = current_time - self.frame_timestamps[frame_id]
            self.frame_timestamps[frame_id] = current_time
            return interval
        else:
            self.frame_timestamps[frame_id] = current_time
            return None


    # 设置UDS参数的函数
    def Set_param(self, uds_handle, chn_param):
        """
        设置UDS的传输层和应用层参数。
        :param uds_handle: UDS句柄
        :param chn_param: 通道参数
        """
        try:
            # 传输层参数
            param_15765 = ZUDS_ISO15765_PARAM()
            memset(byref(param_15765), 0, sizeof(param_15765))
            param_15765.version = chn_param.trans_version
            param_15765.max_data_len = 64 if chn_param.trans_version else 8
            param_15765.local_st_min = 0
            param_15765.block_size = 8
            param_15765.fill_byte = 0
            param_15765.frame_type = chn_param.Extend_Flag
            param_15765.is_modify_ecu_st_min = 0
            param_15765.remote_st_min = 0
            param_15765.fc_timeout = 100
            param_15765.fill_mode = 1
            self.zudslib.Uds_SetParam(uds_handle, 1, param_15765)

            # 应用层参数
            param_seesion = ZUDS_SESSION_PARAM()
            memset(byref(param_seesion), 0, sizeof(param_seesion))
            param_seesion.timeout = 2000
            param_seesion.enhanced_timeout = 5000
            self.zudslib.Uds_SetParam(uds_handle, 0, param_seesion)
            logging.info("set_param completed")
        except Exception as e:
            logging.error(f"Error setting parameters: {e}")

    # 自定义日志记录函数，将日志写入文件
    def log_to_file(self,message):
        global SAVE_LOG_FLAG, LOG_FILE_NAME
        if SAVE_LOG_FLAG:
            try:
                # 获取日志文件所在的目录
                log_dir = os.path.dirname(LOG_FILE_NAME)
                # 如果目录不存在，则创建目录
                if log_dir and not os.path.exists(log_dir):
                    os.makedirs(log_dir)
                with open(LOG_FILE_NAME, 'a', encoding='utf-8') as f:
                    current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    # log_line = f'{current_time} - INFO - {message}\n'
                    log_line = f'{message}\n'
                    f.write(log_line)
            except Exception as e:
                print(f"Error writing to log file: {e}")

    # 开始保存日志
    def start_logging(self, file_name):
        global SAVE_LOG_FLAG, LOG_FILE_NAME
        LOG_FILE_NAME = file_name
        SAVE_LOG_FLAG = True
        self.log_to_file("Logging started.")

    # 停止保存日志
    def stop_logging(self):
        global SAVE_LOG_FLAG
        self.log_to_file("Logging stopped.")
        SAVE_LOG_FLAG = False

    # 接收线程函数，用于接收CAN或CANFD数据并传递给UDS库处理
    def Read_Thread_Func(self, chn_handle, uds_handle):
        """
        接收线程函数，用于接收CAN或CANFD数据并传递给UDS库处理。
        :param chn_handle: 通道句柄
        :param uds_handle: UDS句柄
        """
        try:
            uds_frame = ZUDS_FRAME()
            while START_RECEIVE_FLAG:
                rcv_num = self.zcanlib.GetReceiveNum(chn_handle, ZCAN_TYPE_CAN)
                rcv_canfd_num = self.zcanlib.GetReceiveNum(chn_handle, ZCAN_TYPE_CANFD)
                if rcv_num:
                    rcv_msg, rcv_num = self.zcanlib.Receive(chn_handle, rcv_num, 1)
                    for i in range(rcv_num):
                        memset(byref(uds_frame), 0, sizeof(uds_frame))
                        uds_frame.id = rcv_msg[i].frame.can_id & 0x1fffffff
                        uds_frame.extend = rcv_msg[i].frame.eff
                        uds_frame.data_len = rcv_msg[i].frame.can_dlc
                        for j in range(uds_frame.data_len):
                            uds_frame.data[j] = rcv_msg[i].frame.data[j]
                        data_str = ' '.join(f'{rcv_msg[i].frame.data[j]:02x}' for j in range(rcv_msg[i].frame.can_dlc))
                        self.log_to_file(f"{rcv_msg[i].timestamp}, type: CAN, id: {hex(rcv_msg[i].frame.can_id)}, dlc: {rcv_msg[i].frame.can_dlc}, eff: {rcv_msg[i].frame.eff}, rtr: {rcv_msg[i].frame.rtr}, data: {data_str}")
                        self.zudslib.Uds_Onreceive(uds_handle, uds_frame)
                         # 新增间隔检测
                        interval = self.get_frame_interval(rcv_msg[i].frame.can_id)
                        # if interval is not None:
                        #     logging.info(f"Frame ID 0x{rcv_msg[i].frame.can_id:X} interval: {interval*1000:.2f}ms")

                        frame_id = rcv_msg[i].frame.can_id
                        data = [rcv_msg[i].frame.data[j] for j in range(rcv_msg[i].frame.can_dlc)]
                        self._handle_received_signal(frame_id, data)

                if rcv_canfd_num:
                    rcv_canfd_msgs, rcv_canfd_num = self.zcanlib.ReceiveFD(chn_handle, rcv_canfd_num, 1)
                    for i in range(rcv_canfd_num):
                        memset(byref(uds_frame), 0, sizeof(uds_frame))
                        uds_frame.id = rcv_canfd_msgs[i].frame.can_id & 0x1fffffff
                        uds_frame.extend = rcv_canfd_msgs[i].frame.eff
                        uds_frame.data_len = rcv_canfd_msgs[i].frame.len
                        for j in range(uds_frame.data_len):
                            uds_frame.data[j] = rcv_canfd_msgs[i].frame.data[j]
                        data_str = ' '.join(f'{rcv_canfd_msgs[i].frame.data[j]:02x}' for j in range(rcv_canfd_msgs[i].frame.len))
                        self.log_to_file(f"{rcv_canfd_msgs[i].timestamp}, type: canfd,  id: {hex(rcv_canfd_msgs[i].frame.can_id)}, len: {rcv_canfd_msgs[i].frame.len}, eff: {rcv_canfd_msgs[i].frame.eff}, rtr: {rcv_canfd_msgs[i].frame.rtr}, esi: {rcv_canfd_msgs[i].frame.esi}, brs: {rcv_canfd_msgs[i].frame.brs}, data: {data_str}")
                        self.zudslib.Uds_Onreceive(uds_handle, uds_frame)
                        # 新增间隔检测
                        interval = self.get_frame_interval(rcv_canfd_msgs[i].frame.can_id)
                        # if interval is not None:
                        #     logging.info(f"CANFD Frame ID 0x{rcv_canfd_msgs[i].frame.can_id:X} interval: {interval*1000:.2f}ms")

                        frame_id = rcv_canfd_msgs[i].frame.can_id  
                        data = [rcv_canfd_msgs[i].frame.data[j] for j in range(rcv_canfd_msgs[i].frame.len)]
                        self._handle_received_signal(frame_id, data)
                time.sleep(0.01)
            logging.info("exit receive")
        except Exception as e:
            logging.error(f"Error in Read_Thread_Func: {e}")

    # 打开CAN设备并初始化通道的函数
    def Open_CAN(self):
        """
        打开CAN设备并初始化通道。
        :return: 设备句柄和通道句柄
        """
        try:
            # 打开设备
            self.device_handle = self.zcanlib.OpenDevice(self.device_type, self.device_index, 0)
            if self.device_handle == INVALID_DEVICE_HANDLE:
                logging.error("Open CANFD Device failed!")
                return None, None
            logging.info(f"Open CANFD Device success! device handle: 0x{self.device_handle:x}.")

            # 初始化并启动通道，同时开启队列发送模式
            self.chn_handle_0 = canfd_start(self.zcanlib, self.device_handle, self.chn_index, self.abit, self.bbit)
            logging.info(f"chn handle: 0x{self.chn_handle_0:x}.")
            return self.device_handle, self.chn_handle_0
        except Exception as e:
            logging.error(f"Error opening CAN device: {e}")
            return None, None
        
    def parse_dbc_to_list(self,dbcfile):
        """
        初始化DBC文件。
        :param dbcfile: DBC文件路径
        """
        try:
            self.zdbclib.load_dbc_file(dbcfile)
            logging.info(f"Load DBC file: {dbcfile} success!")
            signal_configs = self.zdbclib.parse_messages_to_list(1)
            return signal_configs
        except Exception as e:
            logging.error(f"Error loading DBC file: {e}")
            return []
        
    def handle_negative_response(self, response, recvData):
        """
        处理消极响应，记录日志并将相关数据添加到 recvData 列表中。
        :param response: UDS 响应结构体
        :param recvData: 用于存储接收数据的列表
        """
        # logging.info(f"消极响应：{hex(response.response.negative.neg_code)} 服务号： {hex(response.response.negative.sid)}  消极码： {hex(response.response.negative.error_code)}")
        recvData.append(response.response.negative.neg_code)
        # 这里原代码可能有误，消极响应没有 positive 相关属性，推测应该是添加消极响应的 sid 和 error_code
        recvData.append(response.response.negative.sid)
        recvData.append(response.response.negative.error_code)

        return recvData

    def handle_positive_response(self, response, recvData):
        """
        处理积极的响应，记录日志并将相关数据添加到 recvData 列表中。
        :param response: UDS 响应结构体
        :param recvData: 用于存储接收数据的列表
        """
        # logging.info(f"积极的响应,响应id:{hex(response.response.positive.sid)},参数长度:{response.response.positive.param_len},参数内容：{' '.join(hex(response.response.positive.param[i]) for i in range(response.response.positive.param_len))}")
        recvData.append(response.response.positive.sid)
        for i in range(response.response.positive.param_len):
             recvData.append(response.response.positive.param[i])

        return recvData
        

    # 发送UDS请求并处理响应的函数
    def requst_response(self, sid, data_1, udsFun = False, enblePrint = True):
        """
        发送UDS请求并处理响应。
        :param sid: 服务ID
        :param data_1: 请求参数
        """
        try:
            request = ZUDS_REQUEST()
            memset(byref(request), 0, sizeof(request))
            if udsFun:
                request.src_addr = 0x7ff#Set_up.AFctID
                request.dst_addr = 0x674#Set_up.resID
            else:
                request.src_addr = 0x774#Set_up.reqID
                request.dst_addr = 0x674#Set_up.resID
            request.sid = sid
            request.suppress_response = 0
            request.param_len = len(data_1)
            param_data = PARAM_DATA()
            for i in range(request.param_len):
                param_data.data[i] = data_1[i]
            request.param = param_data.data
            response = ZUDS_RESPONSE()

            reqData = []
            reqData.append(sid)
            reqData.extend(data_1)


            self.zudslib.Uds_Request(self.uds_handle, request, response)
            memset(byref(param_data), 0, sizeof(param_data))

            recvData = []

            status_messages = {
                0: {
                    0: lambda recvData: self.handle_negative_response(response, recvData),
                    1: lambda recvData: self.handle_positive_response(response, recvData)
                },
                # 1: lambda: logging.info("响应超时"),
                # 2: lambda: logging.info("传输失败，请检查链路层，或请确认流控帧是否回复"),
                # 3: lambda: logging.info("取消请求"),
                # 4: lambda: logging.info("抑制响应"),
                # 5: lambda: logging.info("忙碌中"),
                # 6: lambda: logging.info("请求参数错误")
            }

            if response.status in status_messages:
                if response.status == 0:
                    if response.type in status_messages[0]:
                        # 传入 recvData 参数
                        recvData = status_messages[0][response.type](recvData)
                else:
                    # 这里原代码 lambda 没参数，保持调用方式
                    status_messages[response.status]()
            if enblePrint:
                sendstr = binascii.b2a_hex(bytearray(reqData),' ')
                logging.info('Send UDS ID : [0x{0:X}]'.format(request.src_addr))
                logging.info('Send UDS request size :{0} ---,the send data are <<<{1}>>>'.format(len(reqData),sendstr))

                readstr = binascii.b2a_hex(bytearray(recvData),' ')
                logging.info('Read UDS reponse size :{0} ---,the read data are <<<{1}>>>\n'.format(len(recvData),readstr))

            return recvData, len(recvData)
        except Exception as e:
            logging.error(f"Error in requst_response: {e}")

    # 初始化UDS的函数
    def init_uds(self):
        """
        初始化UDS。
        :return: UDS句柄、通道参数和接收线程
        """
        try:
            self.uds_handle = self.zudslib.Uds_Init(0)
            if self.uds_handle is None:
                raise ValueError("UDS初始化失败")
            logging.info(f"uds_handle: 0x{self.uds_handle:x}.")

            self.chn_param = CHANNEL_PARAM()
            self.chn_param.channel_handle = self.chn_handle_0
            self.chn_param.Extend_Flag = 0
            self.chn_param.CANFD_type = 1
            self.chn_param.trans_version = 1

            self.Set_param(self.uds_handle, self.chn_param)

            ret = self.zudslib.Uds_SetTransmitHandler(self.uds_handle, byref(self.chn_param))
            if ret != 0:
                raise ValueError("Uds_SetTransmitHandler 调用失败")
            logging.info("Uds_SetTransmitHandler success")

            global START_RECEIVE_FLAG
            START_RECEIVE_FLAG = 1
            self.read_thread_ = threading.Thread(target=self.Read_Thread_Func, args=(self.chn_handle_0, self.uds_handle))
            self.read_thread_.start()

            return self.uds_handle, self.chn_param, self.read_thread_
        except Exception as e:
            logging.error(f"初始化UDS时发生错误: {e}")
            return None, None, None

    # 关闭CAN设备和UDS库的函数
    def close_can(self):
        """
        关闭CAN设备和UDS库。
        """
        try:
            time.sleep(1)
            global START_RECEIVE_FLAG
            START_RECEIVE_FLAG = 0
            if self.read_thread_.is_alive():
                self.read_thread_.join()

            if self.uds_handle is not None:
                self.zudslib.Uds_Release(self.uds_handle)

            if self.chn_handle_0 is not None:
                ret = self.zcanlib.ResetCAN(self.chn_handle_0)
                if ret == 1:
                    logging.info("ResetCAN success! ")

            if self.device_handle is not None:
                ret = self.zcanlib.CloseDevice(self.device_handle)
                if ret == 1:
                    logging.info("CloseDevice success! ")

            self.zdbclib.__del__()
        except Exception as e:
            logging.error(f"关闭CAN设备时发生错误: {e}")

    def send_frame(self, ID, Data, type = "CANFD"):
        transmit_num = 1
        if type == "CAN":
            # 发送 CAN 报文
            msgs = (ZCAN_Transmit_Data * transmit_num)()
            for i in range(transmit_num):
                msgs[i].transmit_type = 0  # 0-正常发送，2-自发自收
                msgs[i].frame.eff = 0  # 0-标准帧，1-扩展帧
                msgs[i].frame.rtr = 0  # 0-数据帧，1-远程帧
                msgs[i].frame.can_id = ID  # ID
                msgs[i].frame.can_dlc = len(Data)  # 数据长度
                # msgs[i].frame.__pad =0x20  #回显标志位
                for j in range(msgs[i].frame.can_dlc):
                    msgs[i].frame.data[j] = Data[i]
            ret = zcanlib.Transmit(self.chn_handle_0, msgs, transmit_num)    # 发送
        else:
            # 发送 CANFD 报文
            canfd_msgs = (ZCAN_TransmitFD_Data * transmit_num)()
            for i in range(transmit_num):
                canfd_msgs[i].transmit_type = 0  # 0-正常发送，2-自发自收
                canfd_msgs[i].frame.eff = 0  # 0-标准帧，1-扩展帧
                canfd_msgs[i].frame.rtr = 0  # 0-数据帧，1-远程帧
                canfd_msgs[i].frame.brs = 1  # BRS 加速标志位：0不加速，1加速
                canfd_msgs[i].frame.can_id = ID  # ID
                canfd_msgs[i].frame.len = len(Data)  # 数据长度
                # canfd_msgs[i].frame.__pad  =0x08  #回显标志位
                for j in range(canfd_msgs[i].frame.len):
                    canfd_msgs[i].frame.data[j] = Data[j]
            ret = zcanlib.TransmitFD(self.chn_handle_0, canfd_msgs, transmit_num)  # 发送

    
    def monitor_signal_changes(self):
        """信号监控线程主函数"""
        previous_data = {}
        while self.signal_monitor_running.is_set():
            for signal_id in list(self.signal_data_dict.keys()):
                current_data = self.signal_data_dict.get(signal_id, [])
                # 首次记录或数据长度变化时触发更新
                if signal_id not in previous_data or len(current_data) != len(previous_data[signal_id]):
                    self._trigger_callback(signal_id, "INIT" if signal_id not in previous_data else "LENGTH_CHANGE")
                    previous_data[signal_id] = current_data.copy()
                    continue
                
                # 检查数据内容变化
                if current_data != previous_data[signal_id]:
                    changed_indices = [i for i, (curr, prev) in enumerate(zip(current_data, previous_data[signal_id])) if curr != prev]
                    self._trigger_callback(signal_id, "DATA_CHANGE", changed_indices)
                    previous_data[signal_id] = current_data.copy()
            
            time.sleep(self.signal_monitor_interval)

    def _trigger_callback(self, signal_id, change_type, changed_indices=None):
        """触发注册的回调函数"""
        if signal_id in self.signal_change_callbacks:
            try:
                self.signal_change_callbacks[signal_id](
                    signal_id,
                    self.signal_data_dict[signal_id],
                    change_type,
                    changed_indices
                )
            except Exception as e:
                logging.error(f"Signal callback error for ID {hex(signal_id)}: {str(e)}")

    def register_signal_monitor(self, signal_id, callback, interval=0.1):
        """
        注册信号监控
        :param signal_id: 要监控的信号ID
        :param callback: 回调函数格式: func(signal_id, current_data, change_type, changed_indices)
        :param interval: 监控间隔（秒）
        """
        self.signal_monitor_interval = interval
        self.signal_change_callbacks[signal_id] = callback
        
        # 首次启动监控线程
        if not self.signal_monitor_running.is_set():
            self.signal_monitor_running.set()
            self.signal_monitor_thread = threading.Thread(target=self.monitor_signal_changes)
            self.signal_monitor_thread.daemon = True
            self.signal_monitor_thread.start()

    def unregister_signal_monitor(self, signal_id):
        """注销信号监控"""
        if signal_id in self.signal_change_callbacks:
            del self.signal_change_callbacks[signal_id]


    def stop_all_monitoring(self):
        """停止所有监控"""
        self.signal_monitor_running.clear()
        self.signal_change_callbacks.clear()

    def send_signal_frame_loop(self, ID, signal_data, type="CANFD", interval=500):
        """
        循环发送指定信号CANFD帧的线程函数
        :param ID: 帧ID
        :param signal_data: 信号帧数据
        :param type: 帧类型，默认为CANFD
        :param interval: 发送间隔，默认为500ms
        """
        self.signal_data_dict[ID] = signal_data  # 初始化信号数据
        stop_event = self.signal_stop_event_dict[ID]
        pause_event = self.signal_pause_event_dict[ID]
        self.signal_cantype_dict[ID] = type

         # 新增时间补偿机制
        next_time = time.perf_counter()  # 使用高精度计时器
        # 新增：强制最小间隔
        interval = max(5, interval)  # 设置最小间隔为10ms
        interval_sec = interval / 1000    # 转换为秒

        while not stop_event.is_set():
            pause_event.wait()
            
            # 精确等待到下一个时间点
            while time.perf_counter() < next_time:
                if sys.platform == 'win32':
                    ctypes.windll.kernel32.SleepEx(1, True)  # 使用Windows API精确等待1ms
                else:
                    time.sleep(0.001)
            
            current_data = self.signal_data_dict.get(ID)
            if current_data:
                self.send_frame(ID, current_data, type)
            
            next_time += interval_sec  # 更新下次触发时间

    def start_multiple_signal_loops(self, signal_configs):
        """
        启动多个信号循环发送线程
        :param signal_configs: 从DBC解析的信号配置列表，每个元素为消息字典
        """
        for msg_config in signal_configs:
            msg_id = msg_config['id']
            cycle = msg_config['cycle_ms']
            can_type = 1 if msg_config['is_canfd'] else 0
            signal_data = msg_config['data']
             # 新增：校验周期参数有效性
            if cycle <= 0:
                logging.warning(f"Invalid cycle time {cycle}ms for ID 0x{msg_id:03X}, using default 10ms")
                cycle = 5  # 默认最小周期设为10ms

            if can_type == 1:
                can_type_str = "CANFD"
            else:
                can_type_str = "CAN"

            logging.info(f"Starting signal loop for ID 0x{msg_id:03X} with cycle {cycle} ms and type {can_type_str}")
                 
                
            stop_event = threading.Event()
            pause_event = threading.Event()
            pause_event.set()
            self.signal_stop_event_dict[msg_id] = stop_event
            self.signal_pause_event_dict[msg_id] = pause_event
                
            signal_thread = threading.Thread(
                target=self.send_signal_frame_loop, 
                args=(msg_id, signal_data, can_type_str, cycle)
            )
            signal_thread.daemon = True
            signal_thread.start()
            self.signal_thread_dict[msg_id] = signal_thread

    def update_signal_data(self, ID, new_data=None, index=None, valueBytes=None, signal_name = '', value = None):
        """
        更新指定信号ID的数据（支持整体更新或按字节位置更新）
        :param ID: 信号ID
        :param new_data: 新的完整数据（可选）
        :param index: 要更新的字节位置（支持单个位置或位置列表）
        :param value: 要更新的字节值（支持单个值或值列表）
        """
        if ID not in self.signal_data_dict:
            logging.warning(f"No signal data found for ID {hex(ID)}")
            return

        # 按字节更新模式
        if index is not None and valueBytes is not None:
            current_data = self.signal_data_dict[ID].copy()
            
            # 统一处理为列表格式
            indices = [index] if isinstance(index, int) else index
            values = [valueBytes] if isinstance(valueBytes, int) else valueBytes
            
            if len(indices) != len(values):
                logging.error("索引列表和值列表长度不一致")
                return

            for i, v in zip(indices, values):
                if 0 <= i < len(current_data):
                    current_data[i] = v & 0xFF  # 确保值在0-255范围内
                else:
                    logging.error(f"无效索引 {i}，数据长度为 {len(current_data)}")
            hex_data = ' '.join(f"0x{x:02X}" for x in current_data)
            logging.info(f"Updated signal data for ID {hex(ID)}: {hex_data}")
            
            self.signal_data_dict[ID] = current_data
        # 整体数据更新模式
        elif new_data is not None:
            self.signal_data_dict[ID] = new_data
            # hex_data = ' '.join(f"0x{x:02X}" for x in new_data)
            # logging.info(f"Updated signal data for ID {hex(ID)}: {hex_data}")
        else:
            # 修改为使用常量定义
            frame_type = FT_CANFD if self.signal_cantype_dict[ID] == "CANFD" else FT_CAN
            # 获取当前数据副本
            current_data = self.signal_data_dict.get(ID, []).copy()
            hex_data = ' '.join(f"0x{b:02X}" for b in current_data)
            # logging.info(f'获取信号{signal_name}现数据成功，数据内容: {hex_data}')

            tranData = self.zdbclib.update_signal_value(ID, signal_name, value, frame_type, current_data)

            # 增加数据有效性校验
            if tranData:
                # 转换c_ubyte数组为bytes类型
                if frame_type == FT_CANFD:
                    data_length = tranData.frame.len  # 获取实际数据长度
                else:
                    data_length = tranData.frame.can_dlc
                # 仅更新变化的字节
                updated_data = list(bytes(tranData.frame.data)[:data_length])
                # 保留未修改的字节
                merged_data = current_data[:]
                for i in range(min(len(updated_data), len(merged_data))):
                    if merged_data[i] != updated_data[i]:
                        merged_data[i] = updated_data[i]
                
                self.signal_data_dict[ID] = merged_data  # 存储合并后的数据
                
                hex_data = ' '.join(f"0x{b:02X}" for b in merged_data)
                logging.info(f"Updated signal data for ID {hex(ID)}: {hex_data}")
                # logging.info(f'更新信号{signal_name}值成功，数据内容: {hex_data}')
            else:
                logging.error(f"更新信号{signal_name}值失败，无效返回数据")

    def stop_signal_loop(self, ID):
        """
        停止指定信号的发送线程
        :param ID: 信号ID
        """
        if ID in self.signal_stop_event_dict:
            stop_event = self.signal_stop_event_dict[ID]
            stop_event.set()
            if ID in self.signal_thread_dict:
                thread = self.signal_thread_dict[ID]
                if thread.is_alive():
                    thread.join()
                del self.signal_thread_dict[ID]
                del self.signal_stop_event_dict[ID]
                del self.signal_data_dict[ID]
                del self.signal_pause_event_dict[ID]
            # logging.info(f"Stopped signal loop for ID {hex(ID)}")
        else:
            logging.warning(f"No signal loop found for ID {hex(ID)}")

    def pause_signal_loop(self, ID):
        """
        挂起指定信号的发送线程
        :param ID: 信号ID
        """
        # 添加ID类型验证
        if not isinstance(ID, (int, str)):
            raise TypeError(f"ID必须为可哈希类型(int/str)，当前类型为{type(ID)}")
        if ID in self.signal_pause_event_dict:
            pause_event = self.signal_pause_event_dict[ID]
            pause_event.clear()  # 清除事件以挂起线程
            logging.info(f"Paused signal loop for ID {hex(ID)}")
        else:
            logging.warning(f"No signal loop found for ID {hex(ID)}")

    def resume_signal_loop(self, ID):
        """
        恢复指定信号的发送线程
        :param ID: 信号ID
        """
        # 添加ID类型验证
        if not isinstance(ID, (int, str)):
            raise TypeError(f"ID必须为可哈希类型(int/str)，当前类型为{type(ID)}")
            
        if ID in self.signal_pause_event_dict:
            pause_event = self.signal_pause_event_dict[ID]
            pause_event.set()  # 设置事件以恢复线程
            logging.info(f"Resumed signal loop for ID {hex(ID)}")
        else:
            logging.warning(f"No signal loop found for ID {hex(ID)}")

    def get_signal_config_by_id(self, ID, signal_configs, signal_data, Cantype, cycle):
        """
        通过ID获取signal_configs里对应的值，如果没找到就新增信号
        :param ID: 要查找的ID
        :param signal_configs: 信号配置列表
        :return: 如果找到匹配的ID，返回对应的配置元组；否则新增信号并返回新增的配置元组
        """
        for config in signal_configs:
            if config[0] == ID:
                return config

        # 如果没找到，新增信号
        new_config = (ID, signal_data, Cantype, cycle)  # 这里假设新增的默认值为 (0, 0, 0)，你可以根据实际情况修改
        return new_config
    
    def restart_signal_loop(self, ID, signal_data=[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], Cantype="CANFD", cycle=500):
        """
        重新启动指定信号的发送线程
        :param ID: 信号ID
        :param signal_data: 信号帧数据
        :param type: 帧类型，默认为CANFD
        :param interval: 发送间隔，默认为1秒
        """
        configs =  self.get_signal_config_by_id(ID, Set_up.signal_configs, signal_data, Cantype, cycle)

        if ID not in self.signal_thread_dict:
            stop_event = threading.Event()
            self.signal_stop_event_dict[ID] = stop_event
            signal_thread = threading.Thread(target=self.send_signal_frame_loop, args=(configs[0], configs[1], configs[2], configs[3]))
            signal_thread.daemon = True  # 设置为守护线程，主线程退出时自动退出
            signal_thread.start()
            self.signal_thread_dict[ID] = signal_thread
            self.signal_data_dict[ID] = signal_data
            # logging.info(f"Restarted signal loop for ID {hex(ID)}")
        else:
            logging.warning(f"Signal loop for ID {hex(ID)} is already running")
            

    def search_DTC(self, DTC_CMD,expect_DTC,timeout=5):
        start_time = time.time()
        Find_DTC = False
        rep_value = []
        while( (time.time()-start_time) < timeout):
            rep_value,rep_size = self.requst_response(DTC_CMD[0],DTC_CMD[1:], enblePrint=False)
            reponse_np = np.array(rep_value)[3:].reshape((-1,4))
            for data in reponse_np.tolist():
                # 根据expect_DTC长度进行切片匹配
                compare_length = min(len(expect_DTC), len(data))
                if list(expect_DTC[:compare_length]) == data[:compare_length]:
                    Find_DTC = True
                    break
                else:
                    Find_DTC = False
            if Find_DTC:
                break
        sendstr = binascii.b2a_hex(bytearray(DTC_CMD),' ')    
        totle_time = time.time()-start_time
        all_reponse = binascii.b2a_hex(bytearray(rep_value),' ')
        logging.info('Read DTC by CMD:{0}---,DTC [{4}] had found {1}---,Totle used time {2} ---, The All reponse are {3} '.format(
            sendstr,Find_DTC,totle_time,all_reponse, binascii.b2a_hex(bytearray(expect_DTC), ' ')))
        
        return Find_DTC,totle_time,rep_value
 
        
if __name__ == "__main__":
    uds_controller = UDSController()
    device_handle, chn_handle_0 = uds_controller.Open_CAN()
    uds_handle, chn_param, read_thread_ = uds_controller.init_uds()

    
    
    # # 定义更多信号的配置
    # signal_configs = Set_up.signal_configs
    
    # 修改调用方式（原代码中的函数定义需要删除）
    dbc_path = os.path.join(grand_parent_dir, "data/Kunlun_ETC_BodyCANFD_240501.dbc")
    db = DBCParser(dbc_path)
    signal_configs = db.parse_signals()

    logging.info(signal_configs)
    
    # 启动多个信号循环发送线程
    uds_controller.start_multiple_signal_loops(signal_configs)
    time.sleep(1)
    # 更改信号值
    for i in range(1):
            high_byte = (i >> 8) & 0xFF
            low_byte = i & 0xFF
            speed_data = [high_byte, low_byte]
            new_speed_data =speed_data +  [0x80, 0x00, 0x00, 0x00, 0x0, 0x00]
            uds_controller.update_signal_data(0x106, signal_name='VehicleSpeed', value=i)
            time.sleep(2)
            if i > 3:
                uds_controller.pause_signal_loop(0x90)
            if i > 5:
                uds_controller.resume_signal_loop(0x90)
    
    uds_controller.requst_response(0x10, [0x05])
    uds_controller.close_can()